#ifndef GAMEPHYSICS_H
#define GAMEPHYSICS_H

#include "btBulletCollisionCommon.h"
#include "btBulletDynamicsCommon.h"
#include "GameMotionState.h"
#include "BtOgreExtras.h"
#include "OGRE\OgreSceneManager.h"
#include "BaseObject.h"

typedef std::pair<const btRigidBody*, const btRigidBody*> CollisionPair;
typedef std::set<CollisionPair> CollisionSet;

// This fuction is called every tick
// and adds collisions in the collisionlist of GamePhysics
static void collisionTickCallback(btDynamicsWorld *world, btScalar timeStep);

class GamePhysics
{
public:
	GamePhysics(void);
	~GamePhysics(void);
	bool init(Ogre::SceneManager* scm);
	void update(const unsigned long elapsedTime);
	void addBody(BaseObjectPtr &obj);
	//void addTrigger(TriggerObjectPtr &obj);
	void removeBody(btRigidBody *body);
	btDynamicsWorld *getDynamicsWorld(void);
	BtOgre::DebugDrawer *getDebugDrawer(void);
	CollisionSet getLastCollisionSet() const;
	void setLastCollisionSet(const CollisionSet set);
	void applyGravity(BaseObjectPtr obj);
	void applyOrientation(BaseObjectPtr obj);
	void snapToRail(BaseObjectPtr obj, bool force = false);
	void forceSnapToRail(BaseObjectPtr obj);
	btVector3 GamePhysics::getFinIntersection(void) const;
	// This function checks if there is a collision between objects
	// or object and trigger and sends the right event to the EventManger
	void sendCollisionEvent(const ObjectPtr obj0, const ObjectPtr obj1, const btPersistentManifold *manifold) const;
	// This function sends a ray in a direction to find a hit
	bool raycast(const btVector3 &Start, btVector3 &End, btVector3 &Normal, short mask);
	bool raycast(const btVector3 &Start, btVector3 &End, btVector3 &Normal, btTransform &Trans, short mask);
	bool raycast(const btVector3 &Start, btVector3 &End, btVector3 &Normal, btTransform &Trans,btRigidBody*& body, short mask);
	void getDirectionVecs(btVector3 &pos, btVector3 &right) const;
private:
	// Bullet relevant classes
	btBroadphaseInterface* mpBroadphase;
	btDefaultCollisionConfiguration* mpCollisionConfiguration;
	btCollisionDispatcher* mpDispatcher;
	btSequentialImpulseConstraintSolver* mpSolver;
    btDiscreteDynamicsWorld* mpDynamicsWorld;
	BtOgre::DebugDrawer* mpDebugDrawer;
	Ogre::SceneManager* mpSceneMgr;
	// Collisions from the last frame
	CollisionSet mLastCollisionSet;
	// Last intersection between mouse direction and fin
	btVector3 mFinIntersection;
	btRigidBody *mpStaticBody;
	btVector3 mMousePos;
	btVector3 mCamRight;
};

#endif